home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 3 / Cream of the Crop 3.iso / comm / wnos5src.zip / BBS.C < prev    next >
C/C++ Source or Header  |  1993-10-08  |  45KB  |  2,139 lines

  1. /* Bulletin Board System */
  2. /* @(#) $Header: bbs.c,v 2.40(WNOS) 92/11/25 12:30:00 deyke Exp $ */
  3. /*
  4.  * This file is based on the original WAMPES file 'bbs.c' from DK5SG
  5.  * ported to WNOS - DB3FL.911209
  6.  */
  7.  
  8. #include <sys/types.h>
  9. #include <stdio.h>
  10. #include <ctype.h>
  11. #include <fcntl.h>
  12. #include <stdlib.h>
  13. #include <string.h>
  14. #include <sys/stat.h>
  15. #include <time.h>
  16. #include <dir.h>
  17. #include <io.h>
  18.  
  19. #include "global.h"
  20. #include "config.h"
  21. #ifdef MAILBOX
  22. #include "socket.h"
  23. #include "smtp.h"        /* for 'Days' and 'Months' */
  24. #include "files.h"
  25. #include "dirutil.h"
  26. #include "bbs.h"
  27. #include "server.h"
  28.  
  29. static char *FInfo      = NULLCHAR;
  30. static char *FNic       = NULLCHAR;
  31. static char *MidSuffix     = "@bbs.net";
  32. static char SendMsg[]     = "Sending message to %s.\n";
  33.  
  34. static char *myhostname = NULLCHAR;
  35. static char *MYHOSTNAME = NULLCHAR;
  36. static int len_myhostname = 0;
  37. static int len_MYHOSTNAME = 0;
  38.  
  39. static char BBSversion[] = "DK5SG-BBS  Revision: WNOS_C(2.40) 93/07/08";
  40. static char Entermsg[] = "Enter message (terminate with ^Z or ***END):\n";
  41. static char Indexfile[] = "index";
  42. static char Nosuchmsg[] = "No such Msg '%s'\n";
  43. static char errstr[] = "The '%s' option requires an argument. Type '? %s' for help.\n";
  44. static char Userstr[] = "\nUser:  %s\nName:  %s\nMyBBS: %s\nLast logout: %s\n\n";
  45.  
  46. static int fdindex = -1;
  47. static int Lock = 0;
  48. static int BbsUser = 0;
  49. static int32 index_len = sizeof(struct index);
  50. static unsigned uindex_len = sizeof(struct index);
  51. static unsigned uinfo_len = sizeof(struct userinfo);
  52.  
  53. #undef DEBUG
  54.  
  55. #ifdef DEBUG
  56. #define errorstop(error) tprintf("BBS-Error %d\n",error)
  57. #else
  58. #define errorstop(error)
  59. #endif
  60.  
  61. static struct user * near get_seq __ARGS((char *username,int flag));
  62. static void near cleanup __ARGS((struct user *user));
  63.  
  64. static void near delete_command __ARGS((struct user *user));
  65. static void near dir_command __ARGS((struct user *user));
  66. static void near f_command __ARGS((struct user *user));
  67. static void near help_command __ARGS((struct user *user));
  68. static void near info_command __ARGS((struct user *user));
  69. static void near list_command __ARGS((struct user *user));
  70. static void near mybbs_command __ARGS((struct user *user));
  71. static void near name_command __ARGS((struct user *user));
  72. static void near quit_command __ARGS((struct user *user));
  73. static void near read_command __ARGS((struct user *user));
  74. static void near reply_command __ARGS((struct user *user));
  75. static void near send_command __ARGS((struct user *user));
  76. static void near status_command __ARGS((struct user *user));
  77. static void near user_command __ARGS((struct user *user));
  78. static void near xcrunch_command __ARGS((struct user *user));
  79.  
  80. static struct cmdtable {
  81.     char *name;
  82.     void near (*func) __ARGS((struct user *user));
  83.     int argc;
  84.     int level;
  85. } cmdtable[] = {
  86.     "?",          help_command,           0,      USER,
  87.     "bye",        quit_command,           0,      USER,
  88.     "delete",     delete_command,         2,      USER,
  89.     "dir",        dir_command,            0,      USER,
  90.     "erase",      delete_command,         2,      USER,
  91.     "exit",       quit_command,           0,      USER,
  92.     "help",       help_command,           0,      USER,
  93.     "info",       info_command,           0,      USER,
  94.     "kill",       delete_command,         2,      USER,
  95.     "list",       list_command,           2,      USER,
  96.     "mybbs",      mybbs_command,          2,      USER,
  97.     "name",          name_command,              2,      USER,
  98.     "quit",       quit_command,           0,      USER,
  99.     "read",       read_command,           2,      USER,
  100.     "reply",      reply_command,          2,      USER,
  101.     "send",       send_command,           2,      USER,
  102.     "status",     status_command,         0,      USER,
  103.     "user",          user_command,            2,      USER,
  104.     "xcrunch",    xcrunch_command,        0,      ROOT,
  105.     "f>",         f_command,              0,      BOX,
  106.     "sb",         send_command,           2,      BOX,
  107.     "sp",         send_command,           2,      BOX,
  108.     0,              0,                      0,      0,
  109. };
  110.  
  111. static char * near
  112. getarg(char *line,int all)
  113. {
  114.   char *arg;
  115.   static char *p;
  116.  
  117.   if(line) {
  118.     p = line;
  119.   }
  120.   while(isspace(uchar(*p))) {
  121.     p++;
  122.   }
  123.   if(all) {
  124.     return p;
  125.   }
  126.   arg = p;
  127.  
  128.   while(*p && !isspace(uchar(*p))) {
  129.     p++;
  130.   }
  131.   if(*p) {
  132.     *p++ = '\0';
  133.   }
  134.   return arg;
  135. }
  136.  
  137. static int near
  138. getstring(struct user *user)
  139. {
  140.     int len = -1;
  141.     usflush(user->s);
  142.  
  143.     if((len = recvline(user->s,user->line,LINELEN)) < 0) {
  144.         return 0;
  145.     }
  146.     return len;
  147. }
  148.  
  149. static void near
  150. wait_for_prompt(struct user *user)
  151. {
  152.     int l = 0;
  153.  
  154.     do {
  155.         if(!getstring(user)) {
  156.             return;
  157.         }
  158.         rip(user->line);
  159.         l = strlen(user->line);
  160.  
  161.     } while (!l || user->line[l-1] != '>');
  162. }
  163.  
  164. static char * near
  165. strtrim(char *s)
  166. {
  167.     char *p;
  168.  
  169.     for(p = s; *p; p++) ;
  170.     while(--p >= s && isspace(uchar(*p))) ;
  171.     p[1] = 0;
  172.     return s;
  173. }
  174.  
  175. static char * near
  176. strcasepos(char *str, char *pat)
  177. {
  178.     char *s, *p;
  179.  
  180.     for(; ; str++) {
  181.         for(s = str, p = pat; ; ) {
  182.             if(!*p) {
  183.                 return str;
  184.             }
  185.             if(!*s) {
  186.                 return 0;
  187.             }
  188.             if(tolower(uchar(*s++)) != tolower(uchar(*p++))) {
  189.                 break;
  190.             }
  191.         }
  192.     }
  193. }
  194.  
  195. static int near
  196. callvalid(char *call)
  197. {
  198.     int d = 0, l = strlen(call);
  199.  
  200.     if(l < 2 || l > 6) {
  201.         return 0;
  202.     }
  203.     if(isdigit(uchar(call[0])) && isdigit(uchar(call[1]))) {
  204.         return 0;
  205.     }
  206.     if(!(isdigit(uchar(call[1])) || isdigit(uchar(call[2])))) {
  207.         return 0;
  208.     }
  209.     if(!isalpha(uchar(call[l-1]))) {
  210.         return 0;
  211.     }
  212.     for(; *call; call++) {
  213.         if(!isalnum(uchar(*call))) {
  214.             return 0;
  215.         }
  216.         if(isdigit(uchar(*call))) {
  217.             d++;
  218.         }
  219.     }
  220.     if(d < 1 || d > 2) {
  221.         return 0;
  222.     }
  223.     return 1;
  224. }
  225.  
  226. static int near
  227. check_eom(char *s,int flag)
  228. {
  229.     if((!flag
  230.       && *s == '\032')
  231.       || strcmp(s,".\n") == 0
  232.       || stricmp(s,"***end\n") == 0
  233.       || stricmp(s,"/ex\n") == 0) {
  234.         if(flag) {
  235.           *s = ' ';
  236.         }
  237.         return 1;
  238.     }
  239.     return 0;
  240. }
  241.  
  242. static int
  243. make_parent_directories(char *filename)
  244. {
  245.     char dirname[MAXPATH], *p;
  246.  
  247.     sprintf(dirname,"%.*s",MAXPATH-1,filename);
  248.  
  249.     if((p = strrchr(dirname,'/')) != NULLCHAR) {
  250.         *p = '\0';
  251.     }
  252.     if(mkdir(dirname) == 0) {
  253.         return 0;
  254.     }
  255.     make_parent_directories(dirname);
  256.  
  257.     return mkdir(dirname);
  258. }
  259.  
  260. static char * near
  261. getfilename(int32 mesg)
  262. {
  263.     static char buf[MAXPATH + 12];
  264.  
  265.     sprintf(buf,"%s/%02lx/%02lx/%02lx/%02lx",
  266.         BBSwrkdir,
  267.         ((mesg >> 24) & 0xff),
  268.         ((mesg >> 16) & 0xff),
  269.         ((mesg >>  8) & 0xff),
  270.         ((mesg      ) & 0xff));
  271.  
  272.     return buf;
  273. }
  274.  
  275. static int near
  276. get_index(int32 n,struct index *index)
  277. {
  278.     int32 i1 = 0, i2 = 0, im = 0, imt = 0, pos = 0;
  279.  
  280.     lseek(fdindex,0,SEEK_SET);
  281.  
  282.     if(read(fdindex,index,uindex_len) != uindex_len) {
  283.         errorstop(1);
  284.         return 0;
  285.     }
  286.     if(n == index->mesg) {
  287.         return 1;
  288.     }
  289.     if(n < index->mesg) {
  290.         return 0;
  291.     }
  292.     if((pos = lseek(fdindex,-index_len,SEEK_END)) < 0) {
  293.         errorstop(2);
  294.         return 0;
  295.     }
  296.     i2 = pos / index_len;
  297.  
  298.     if(read(fdindex,index,uindex_len) != uindex_len) {
  299.         errorstop(3);
  300.         return 0;
  301.     }
  302.     if(n == index->mesg) {
  303.         return 1;
  304.     }
  305.     if(n > index->mesg) {
  306.         return 0;
  307.     }
  308.     while(i1 + 1 < i2) {
  309.         im = (i1 + i2) / 2;
  310.         imt = im * index_len;
  311.  
  312.         if(lseek(fdindex,imt,SEEK_SET) < 0) {
  313.             errorstop(4);
  314.             return 0;
  315.         }
  316.         if(read(fdindex,index,uindex_len) != uindex_len) {
  317.             errorstop(5);
  318.             return 0;
  319.         }
  320.         if(n == index->mesg) {
  321.             return 1;
  322.         }
  323.         if(n > index->mesg) {
  324.             i1 = im;
  325.         } else {
  326.             i2 = im;
  327.         }
  328.     }
  329.     return 0;
  330. }
  331.  
  332. static int near
  333. read_allowed(struct index *index,struct user *user)
  334. {
  335.     switch(index->flag) {
  336.     case DELETED:
  337.         return 0;
  338.     case PRIVATE:
  339.     case NORMAL:
  340.         if(user->level != ROOT) {
  341.             if(stricmp(user->name,index->to) && stricmp(user->name,index->from)) {
  342.                 return 0;
  343.             }
  344.         }
  345.     case BULLETIN:
  346.         if(user->level == ROOT) {
  347.             return 1;
  348.         }
  349.         if(stricmp("THEBOX",index->at) == 0) {
  350.             return 0;
  351.         }
  352.     case NEWS:
  353.         return 1;
  354.     }
  355.     return 0;
  356. }
  357.  
  358. static char * near
  359. get_user_from_path(char *path)
  360. {
  361.     char *cp;
  362.  
  363.     if((cp = strrchr(path,'!')) == NULLCHAR) {
  364.         return path;
  365.     }
  366.     return cp + 1;
  367. }
  368.  
  369. static char * near
  370. get_host_from_path(char *path)
  371. {
  372.     char *cp;
  373.     static char tmp[80];
  374.  
  375.     strcpy(tmp,path);
  376.  
  377.     if((cp = strrchr(tmp,'!')) == NULLCHAR) {
  378.         return myhostname;
  379.     }
  380.     *cp = '\0';
  381.  
  382.     if((cp = strrchr(tmp,'!')) == NULLCHAR) {
  383.         return tmp;
  384.     }
  385.     return cp + 1;
  386. }
  387.  
  388. static char * near
  389. get_host_from_header(char *line)
  390. {
  391.     char *p, *q, buf[80];
  392.  
  393.     if(*line == 'R'
  394.       && line[1] == ':'
  395.       && ((p = strchr(strcpy(buf,line),'@')) != NULLCHAR)) {
  396.         p++;
  397.         while(*p == ':' || isspace(uchar(*p))) {
  398.             p++;
  399.         }
  400.         for(q = p; isalnum(uchar(*q)); q++) ;
  401.         *q = 0;
  402.         return p;
  403.     }
  404.     return NULLCHAR;
  405. }
  406.  
  407. static int near
  408. msg_uniq(char *bid)
  409. {
  410.     struct index pi;
  411.     int32 validdate = currtime - 90 * DAYS;
  412.  
  413.     if(lseek(fdindex,0,SEEK_SET) != 0) {
  414.         errorstop(6);
  415.         return 0;
  416.     }
  417.     while(read(fdindex,&pi,uindex_len) == uindex_len) {
  418.         if(pi.date >= validdate && stricmp(pi.bid,bid) == 0) {
  419.             return 0;
  420.         }
  421.     }
  422.     return 1;
  423. }
  424.  
  425. static int32 near
  426. send_to_bbs(struct mail *mail)
  427. {
  428.   int32 mesg = 0;
  429.  
  430.   if(!*mail->subject) {
  431.     return 0;
  432.   }
  433.   semwait(&Lock,1);
  434.  
  435.   if(msg_uniq(mail->bid) == 1) {
  436.     FILE *fp;
  437.     struct strlist *p;
  438.     struct index index;
  439.  
  440.     if(lseek(fdindex,-index_len,SEEK_END) < 0) {
  441.       mesg = 0;
  442.     } else {
  443.       if(read(fdindex,&index,uindex_len) != uindex_len) {
  444.         errorstop(7);
  445.         goto quit;
  446.       }
  447.       mesg = index.mesg;
  448.     }
  449.     memset(&index,0,uindex_len);
  450.  
  451.     index.mesg = ++mesg;
  452.     index.date = mail->date;
  453.     index.lifetime_h = (mail->lifetime + 1) >> 8;
  454.     index.lifetime_l = (mail->lifetime + 1) & 0x0F;
  455.  
  456.     strcpy(index.bid,mail->bid);
  457.     sprintf(index.subject,"%.*s",LEN_SUBJECT,mail->subject);
  458.     sprintf(index.to,"%.*s",LEN,get_user_from_path(mail->to));
  459.     strupr(index.to);
  460.     sprintf(index.at,"%.*s",LEN,get_host_from_path(mail->to));
  461.     strupr(index.at);
  462.     sprintf(index.from,"%.*s",LEN,get_user_from_path(mail->from));
  463.     strupr(index.from);
  464.     sprintf(index.from_at,"%.*s",LEN,get_host_from_path(mail->from));
  465.     strupr(index.from_at);
  466.  
  467.     index.flag = mail->flag;
  468.     index.size = 0;
  469.  
  470.     if((fp = Fopen(getfilename(index.mesg),WRITE_TEXT,0,0)) == NULLFILE) {
  471.       make_parent_directories(getfilename(index.mesg));
  472.       if((fp = Fopen(getfilename(index.mesg),WRITE_TEXT,0,1)) == NULLFILE) {
  473.         errorstop(10);
  474.         goto quit;
  475.       }
  476.     }
  477.     if(strcmp(index.to,"E") != 0 && strcmp(index.to,"M") != 0) {
  478.       for (p = mail->head; p; p = p->next) {
  479.         fputs(p->str,fp);
  480.         index.size += (strlen(p->str) + 1);
  481.       }
  482.     }
  483.     Fclose(fp);
  484.  
  485.     if(lseek(fdindex,0,SEEK_END) < 0) {
  486.       errorstop(11);
  487.       goto quit;
  488.     }
  489.     if(write(fdindex,&index,uindex_len) != uindex_len) {
  490.       errorstop(12);
  491.       goto quit;
  492.     }
  493.   }
  494. quit:
  495.   semrel(&Lock);
  496.   return mesg;
  497. }
  498.  
  499. static void near
  500. send_to_mail(struct mail *mail)
  501. {
  502.   FILE *fp;
  503.   char *cp, line[LINELEN];
  504.   struct strlist *p;
  505.   int32 msg = get_msgid();
  506.  
  507.   sprintf(line,"%s/%ld.txt",Mailqdir,msg);
  508.  
  509.   if((fp = Fopen(line,WRITE_TEXT,0,1)) != NULLFILE) {
  510.     if(strchr(mail->from,'!') != NULLCHAR) {
  511.       char *tmp = strxdup(mail->from);
  512.  
  513.       *mail->from = '\0';
  514.  
  515.       while((cp = strrchr(tmp,'!')) != NULLCHAR) {
  516.         *cp++ = '\0';
  517.         strcat(mail->from,cp);
  518.         strcat(mail->from,"%");
  519.       }
  520.       strcat(mail->from,tmp);
  521.       xfree(tmp);
  522.     }
  523.     if((cp = strrchr(mail->from,'%')) != NULLCHAR) {
  524.         *cp = '@';
  525.     }
  526.     if(strchr(mail->to,'!') != NULLCHAR) {
  527.       char *tmp = strxdup(mail->to);
  528.  
  529.       *mail->to = '\0';
  530.  
  531.       while((cp = strrchr(tmp,'!')) != NULLCHAR) {
  532.         *cp++ = '\0';
  533.         strcat(mail->to,cp);
  534.         strcat(mail->to,"%");
  535.       }
  536.       strcat(mail->to,tmp);
  537.       xfree(tmp);
  538.     }
  539.     if((cp = strrchr(mail->to,'%')) != NULLCHAR) {
  540.         *cp++ = '@';
  541.     }
  542.     fprintf(fp,"%sby %s (%s)\n\tid AA%ld; %s",
  543.         Hdrs[RECEIVED],Hostname,BBSversion,msg,rfc822_date(&currtime));
  544.     fprintf(fp,"%s%s",
  545.         Hdrs[DATE],rfc822_date(&mail->date));
  546.     fprintf(fp,"%s<%s>\n%s<%s>\n",
  547.         Hdrs[MSGID],mail->mid,Hdrs[BULLID],mail->bid);
  548.     if(mail->lifetime != -1) {
  549.       int32 t = mail->date + (DAYS * mail->lifetime);
  550.       fprintf(fp,"%s%s",Hdrs[EXPIRE],rfc822_date(&t));
  551.     }
  552.     fprintf(fp,"%s%s\n%s%s\n",
  553.         Hdrs[FROM],mail->from,Hdrs[TO],mail->to);
  554.  
  555.     if (*mail->subject) {
  556.       fprintf(fp,"%s%s\n",Hdrs[SUBJECT],mail->subject);
  557.     }
  558.     fputc('\n',fp);
  559.  
  560.     for (p = mail->head; p; p = p->next) {
  561.       fputs(p->str, fp);
  562.     }
  563.     Fclose(fp);
  564.  
  565.     sprintf(line,"%s/%ld.wrk",Mailqdir,msg);
  566.  
  567.     if((fp = Fopen(line,WRITE_TEXT,0,1)) != NULLFILE) {
  568.       fprintf(fp,"%s\n%s\n\%s\n",cp,mail->from,mail->to);
  569.       Fclose(fp);
  570.     }
  571.   }
  572. }
  573.  
  574. #ifdef XXX
  575. static void near
  576. send_to_news(struct mail *mail)
  577. {
  578.   FILE *fp;
  579.   char *fromhost, *pp;
  580.   int fd, i;
  581.   struct strlist *p;
  582.  
  583.   if (!*mail->subject) return;
  584.   if ((fp = fopen("/usr/bin/rnews", "w")) == NULLFILE) _exit(1);
  585.   fromhost = get_host_from_path(mail->from);
  586.   fprintf(fp,"%s%s@%s%s\n",
  587.     Hdrs[FROM],get_user_from_path(mail->from),fromhost,strchr(fromhost, '.') ? "" : ".ampr.org");
  588.   fprintf(fp,"%s%s",
  589.     Hdrs[DATE],rfc822_date(mail->date));
  590.   fprintf(fp,"%sampr.bbs.%s\n",
  591.     Hdrs[NEWSGROUPS],get_user_from_path(mail->to));
  592.   fprintf(fp,"%s%s\n",
  593.     Hdrs[SUBJECT],mail->subject);
  594.   fprintf(fp,"%s<%s>\n",
  595.     Hdrs[MSGID],mail->mid);
  596.  
  597.   i = strlen(Hostname);
  598.  
  599.   if(!strncmp(mail->from,Hostname,i) && mail->from[i] == '!') {
  600.     pp = mail->from + i + 1;
  601.   } else {
  602.     pp = mail->from;
  603.   }
  604.   fprintf(fp,"%s%s\n",
  605.     Hdrs[PATH],pp);
  606.  
  607.   if (mail->lifetime != -1) {
  608.     fprintf(fp,"%s%s",
  609.       Hdrs[EXPIRES],rfc822_date(mail->date + DAYS * mail->lifetime));
  610.   }
  611.   fprintf(fp,"%s%s\n",
  612.     Hdrs[DISTRIBUTION],get_host_from_path(mail->to));
  613.   fprintf(fp,"%s<%s>\n",
  614.     Hdrs[BULLID],mail->bid);
  615.  
  616.   fputc('\n', fp);
  617.  
  618.   p = mail->head;
  619.   while (p && p->str[0] == 'R' && p->str[1] == ':')
  620.     p = p->next;
  621.   while (p
  622.    && (p->str[0] == 'd'
  623.    && p->str[1] == 'e'
  624.    && p->str[2] == ' '
  625.    || p->str[0] == 't'
  626.    && p->str[1] == 'o'
  627.    && p->str[2] == ' '))
  628.     p = p->next;
  629.   while (p && p->str[0] == 0)
  630.     p = p->next;
  631.   while (p) {
  632.     fputs(p->str, fp);
  633.     fputc('\n', fp);
  634.     p = p->next;
  635.   }
  636.   pclose(fp);
  637.   _exit(0);
  638. }
  639. #endif
  640.  
  641. static void near
  642. fix_address(char *addr)
  643. {
  644.     char *p1, *p2, tmp[80];
  645.  
  646.     for (p1 = addr; *p1; p1++) {
  647.         switch (*p1) {
  648.         case '%':
  649. /*        case '.':    */
  650.             *p1 = '@';
  651.             break;
  652.         case ',':
  653.             *p1 = ':';
  654.             break;
  655.         case '^':
  656.             *p1 = '!';
  657.             break;
  658.         }
  659.     }
  660.     while(((p1 = strchr(addr,'@')) != NULLCHAR)
  661.       && ((p2 = strchr(p1,':')) != NULLCHAR)) {
  662.         *p1 = *p2 = 0;
  663.         sprintf(tmp,"%s%s!%s",addr,p1 + 1,p2 + 1);
  664.         strcpy(addr,tmp);
  665.     }
  666.     while((p2 = strrchr(addr,'@')) != NULLCHAR) {
  667.         *p2 = 0;
  668.         p1 = p2;
  669.  
  670.         while (p1 > addr && *p1 != '!') {
  671.             p1--;
  672.         }
  673.         if(p1 == addr) {
  674.             sprintf(tmp,"%s!%s",p2 + 1,addr);
  675.         } else {
  676.             *p1 = 0;
  677.             sprintf(tmp,"%s!%s!%s",addr,p2 + 1,p1 + 1);
  678.         }
  679.         strcpy(addr, tmp);
  680.     }
  681.     if(strchr(addr,'!') == NULLCHAR) {
  682.         sprintf(tmp,"%s!%s",myhostname,addr);
  683.         strcpy(addr,tmp);
  684.     }
  685.     strlwr(addr);
  686. }
  687.  
  688. static struct mail * near
  689. alloc_mail(void)
  690. {
  691.     struct mail *mail = mxallocw(sizeof(struct mail));
  692.  
  693.     mail->lifetime = -1;
  694.     return mail;
  695. }
  696.  
  697. static void near
  698. free_mail(struct mail *mail)
  699. {
  700.     struct strlist *p;
  701.  
  702.     while((p = mail->head) != NULL) {
  703.         mail->head = p->next;
  704.         xfree(p->str);
  705.         xfree(p);
  706.     }
  707.     xfree(mail);
  708. }
  709.  
  710. static void near
  711. route_mail(struct mail *mail,struct user *user,int flag)
  712. {
  713.   char *cp = NULLCHAR;
  714.   struct strlist *p = 0;
  715.  
  716.   /* Set date */
  717.   mail->date = currtime;
  718.  
  719.   /* Fix addresses */
  720.   fix_address(mail->from);
  721.   fix_address(mail->to);
  722.  
  723.   if(mail->flag == NORMAL) {
  724.     if(callvalid(get_user_from_path(mail->to))) {
  725.       mail->flag = PRIVATE;
  726.     } else {
  727.       mail->flag = BULLETIN;
  728.     }
  729.   }
  730.   /* Check for bogus mails */
  731.   strtrim(mail->subject);
  732.  
  733.   if(((cp = get_host_from_header(mail->subject)) != NULLCHAR && callvalid(cp))) {
  734.     goto Done;
  735.   }
  736.   if(user->level == BOX) {
  737.     if((cp = get_user_from_path(mail->to)) == NULLCHAR) {
  738.       goto Done;
  739.     }
  740.     if(strlen(cp) > 1) {
  741.       if(!mail->head) {
  742.         goto Done;
  743.       }
  744.       if((cp = get_host_from_header(mail->head->str)) == NULLCHAR
  745.        || stricmp(cp,user->name) == 0) {
  746.         goto Done;
  747.       }
  748.     }
  749.   }
  750.   /* Set bid */
  751.   if(!*mail->bid && *mail->mid) {
  752.     int i = 0;
  753.     char *cp = mail->mid;
  754.  
  755.     while(*cp != '\0') {
  756.       if(!isalnum(*cp)) {
  757.         if(!i) {
  758.             *cp = '_';
  759.             i = 1;
  760.         } else {
  761.             *cp = '\0';
  762.             break;
  763.         }
  764.       }
  765.       cp++;
  766.     }
  767.     sprintf(mail->bid,"%.12s",mail->mid);
  768.   }
  769.   if(!*mail->bid) {
  770.     sprintf(mail->bid,"%012d",get_msgid());
  771.     strncpy(mail->bid,MYHOSTNAME,min(9,len_MYHOSTNAME));
  772.   }
  773.   strupr(mail->bid);
  774.  
  775.   /* Set mid */
  776.   if(!*mail->mid) {
  777.     sprintf(mail->mid,"%s%s",mail->bid,MidSuffix);
  778.   }
  779.   /* Remove message delimiters */
  780.   for(p = mail->head; p; p = p->next) {
  781.     char *s = p->str;
  782.     if(*s == '.' && !s[1]) {
  783.       *s = 0;
  784.     }
  785.     while((cp = strchr(s,'\032')) != NULLCHAR) {
  786.       while((cp[0] = cp[1]) != 0) {
  787.         cp++;
  788.       }
  789.     }
  790.     check_eom(s,1);
  791.   }
  792.   /* Call delivery agents */
  793.   if(flag == MAIL) {
  794.     send_to_mail(mail);
  795.   } else {
  796.     int32 mesg = send_to_bbs(mail);
  797.  
  798.     if(mesg && (user->info && mesg == (user->info->seq + 1))) {
  799.       user->info->seq = mesg;
  800.     }
  801.   }
  802. Done:
  803.   /* Free mail */
  804.   free_mail(mail);
  805. }
  806.  
  807. static void near
  808. append_line(struct mail *mail,char *line)
  809. {
  810.     struct strlist *p = mxallocw(sizeof(struct strlist));
  811.  
  812.     p->str = strxdup(line);
  813.  
  814.     if (!mail->head) {
  815.         mail->head = p;
  816.     } else {
  817.         mail->tail->next = p;
  818.     }
  819.     mail->tail = p;
  820. }
  821.  
  822. static int near
  823. get_header_value(char *name,char *line,char *value)
  824. {
  825.     char *p1, *p2;
  826.  
  827.     while(*name) {
  828.         if(tolower(uchar(*name++)) != tolower(uchar(*line++))) {
  829.             return 0;
  830.         }
  831.     }
  832.     while(isspace(uchar(*line))) {
  833.         line++;
  834.     }
  835.     while(((p1 = strchr(line, '<')) != NULLCHAR)
  836.       && ((p2 = strrchr(p1, '>')) != NULLCHAR)) {
  837.         *p2 = 0;
  838.         line = p1 + 1;
  839.     }
  840.     strcpy(value,line);
  841.     return 1;
  842. }
  843.  
  844. static int near
  845. host_in_header(char *fname, char *host)
  846. {
  847.   FILE *fp;
  848.  
  849.   if((fp = Fopen(fname,READ_TEXT,0,1)) != NULLFILE) {
  850.     char *p, buf[MAXPATH];
  851.  
  852.     while(fgets(buf,MAXPATH,fp) != NULL) {
  853.       if((p = get_host_from_header(buf)) != NULLCHAR
  854.        && stricmp(p,host) == 0) {
  855.         Fclose(fp);
  856.         return 1;
  857.       }
  858.     }
  859.     Fclose(fp);
  860.   }
  861.   return 0;
  862. }
  863.  
  864. #ifdef XXX
  865. static int near
  866. mail_pending(struct user *user)
  867. {
  868.     char dirname[MAXPATH];
  869.     static int have_mail;
  870.     static int32 nexttime = 0;
  871.  
  872.     if(nexttime > currtime) {
  873.         return have_mail;
  874.     }
  875.     nexttime = currtime + 5 * MINUTES;
  876.     have_mail = 0;
  877.  
  878.     sprintf(dirname,"%s/%s.lck",Mailspool,user->name);
  879.  
  880.     if(access(dirname,0) == 0) {
  881.         have_mail = 1;
  882.     }
  883.     return have_mail;
  884. }
  885. #endif
  886.  
  887. static void near
  888. delete_command(struct user *user)
  889. {
  890.   char *cp;
  891.  
  892.   semwait(&Lock,1);
  893.  
  894.   getarg(user->line,0);
  895.  
  896.   while(*(cp = getarg(0,0))) {
  897.     int32 mesg = 0;
  898.     struct index index;
  899.  
  900.     memset(&index,0,uindex_len);
  901.  
  902.     if((mesg = atol(cp)) > 0
  903.      && get_index(mesg,&index)
  904.      && !(index.flag & DELETED)) {
  905.       if(user->level == ROOT
  906.        || stricmp(index.from,user->name) == 0
  907.        || stricmp(index.to,user->name) == 0) {
  908.         unlink(getfilename(mesg));
  909.         index.flag = DELETED;
  910.  
  911.         if(lseek(fdindex,-index_len,SEEK_CUR) < 0) {
  912.           errorstop(15);
  913.           goto quit;
  914.         }
  915.         write(fdindex,&index,uindex_len);
  916.         usprintf(user->s,"Msg# %d deleted\n", mesg);
  917.       } else {
  918.         usprintf(user->s,"Msg# %d not deleted: Permission denied\n", mesg);
  919.       }
  920.     } else {
  921.       usprintf(user->s,Nosuchmsg,cp);
  922.     }
  923.   }
  924. quit:
  925.   semrel(&Lock);
  926. }
  927.  
  928. static int near
  929. dir_print(struct dir_entry *p,int s)
  930. {
  931.     int i = 0;
  932.  
  933.     if(p) {
  934.         dir_print(p->left,s);
  935.         usprintf(s,(i++ % 5) < 4 ? "%5d %-8s" : "%5d %s\n",p->count,p->to);
  936.         dir_print(p->right,s);
  937.         xfree(p);
  938.     }
  939.     return i;
  940. }
  941.  
  942. static void near
  943. dir_command(struct user *user)
  944. {
  945.     int cmp = 0;
  946.     struct dir_entry *head = 0, *curr = 0, *prev = 0;
  947.     struct index pi;
  948.  
  949.     lseek(fdindex,0,SEEK_SET);
  950.  
  951.     while(read(fdindex,&pi,uindex_len) == uindex_len) {
  952.         if(read_allowed(&pi,user)) {
  953.             for(prev = 0, curr = head; ; ) {
  954.                 if(!curr) {
  955.                     curr = mxallocw(sizeof(struct dir_entry));
  956.                     curr->count = 1;
  957.                     strcpy(curr->to,pi.to);
  958.  
  959.                     if(!prev) {
  960.                         head = curr;
  961.                     } else if (cmp < 0) {
  962.                         prev->left = curr;
  963.                     } else {
  964.                         prev->right = curr;
  965.                     }
  966.                     break;
  967.                 }
  968.                 if((cmp = strcmp(pi.to,curr->to)) == 0) {
  969.                     curr->count++;
  970.                     break;
  971.                 }
  972.                 prev = curr;
  973.                 curr = (cmp < 0) ? curr->left : curr->right;
  974.             }
  975.         }
  976.     }
  977.     if(dir_print(head,user->s) % 4) {
  978.         usputs(user->s,"\n");
  979.     }
  980. }
  981.  
  982. static void near
  983. f_command(struct user *user)
  984. {
  985.   FILE *fp;
  986.   struct index index;
  987.   char line[LINELEN];
  988.   int lifetime, do_not_exit = 0;
  989.  
  990.   semwait(&Lock,1);
  991.  
  992.   if(!get_index(user->info->seq,&index)) {
  993.     lseek(fdindex,0,SEEK_SET);
  994.   }
  995.   semrel(&Lock);
  996.  
  997.   while(read(fdindex,&index,uindex_len) == uindex_len) {
  998.     if(!(index.flag & DELETED)
  999.      && index.mesg > user->info->seq
  1000.      && strnicmp(index.at,MYHOSTNAME,len_MYHOSTNAME) != 0
  1001.      && !host_in_header(getfilename(index.mesg),user->name)) {
  1002. #ifdef XXX
  1003.       if(mail_pending(user)) {
  1004.         return;
  1005.       }
  1006. #endif
  1007.       do_not_exit = 1;
  1008.       lifetime = ((index.lifetime_h << 8) & 0xff00) + (index.lifetime_l & 0xff) - 1;
  1009.  
  1010.       usprintf(user->s,"S %s%s%s < %s%s%s",
  1011.         index.to,
  1012.         *index.at ? " @ " : "",
  1013.         index.at,
  1014.         index.from,
  1015.         *index.bid ? " $ " : "",
  1016.         index.bid);
  1017.  
  1018.       if(lifetime != -1) {
  1019.         usprintf(user->s," # %d",lifetime);
  1020.       }
  1021.       usputs(user->s,"\n");
  1022.  
  1023.       if(!getstring(user)) {
  1024.         return;
  1025.       }
  1026.       switch(tolower(*user->line)) {
  1027.       case 'o':
  1028.         usprintf(user->s,"%s\n",*index.subject ? index.subject : "no subject");
  1029.  
  1030.         if(strcmp(index.to,"E") == 0 || strcmp(index.to,"M") == 0) {
  1031.           usputs(user->s,"\n");
  1032.         } else {
  1033.           struct tm *tm = gmtime(&index.date);
  1034.  
  1035.           usprintf(user->s,"R:%02d%02d%02d/%02d%02dz @:%s.%s [%s]\n",
  1036.             tm->tm_year,
  1037.             tm->tm_mon + 1,
  1038.             tm->tm_mday,
  1039.             tm->tm_hour,
  1040.             tm->tm_min,
  1041.             MYHOSTNAME,
  1042.             FNic ? FNic : MYHOSTNAME,
  1043.             FInfo ? FInfo : Version);
  1044.  
  1045.           if((fp = Fopen(getfilename(index.mesg),READ_TEXT,0,1)) == NULLFILE) {
  1046.             return;
  1047.           }
  1048.           while(fgets(line,LINELEN,fp) != NULL) {
  1049.             usputs(user->s,line);
  1050.           }
  1051.           Fclose(fp);
  1052.         }
  1053.         usputs(user->s,"\032\n");
  1054.       case 'n':
  1055.         wait_for_prompt(user);
  1056.         break;
  1057.       default:
  1058.         return;
  1059.       }
  1060.     }
  1061.     if(user->info->seq < index.mesg) {
  1062.       user->info->seq = index.mesg;
  1063.     }
  1064.   }
  1065.   if(do_not_exit) {
  1066.     usputs(user->s,"F");
  1067.   } else {
  1068.     return;
  1069.   }
  1070. }
  1071.  
  1072. static void near
  1073. help_command(struct user *user)
  1074. {
  1075.   char *cp;
  1076.  
  1077.   getarg(user->line,0);
  1078.  
  1079.   if(!(*(cp = getarg(0,1)))) {
  1080.     int i;
  1081.     struct cmdtable *cmdp;
  1082.  
  1083.     usputs(user->s,"Commands may be abbreviated. Commands are:\n");
  1084.  
  1085.     for (i = 0, cmdp = cmdtable; cmdp->name; cmdp++) {
  1086.       if (user->level >= cmdp->level) {
  1087.         usprintf(user->s,(i++ % 5) < 4 ? "%-15.15s" : "%s\n", cmdp->name);
  1088.       }
  1089.     }
  1090.     if (i % 5) {
  1091.       usputs(user->s,"\n");
  1092.     }
  1093.   } else {
  1094.     gethelp(9980,user->s,cp);
  1095.   }
  1096. }
  1097.  
  1098. static void near
  1099. info_command(struct user *user)
  1100. {
  1101.     FILE *fp;
  1102.     char buf[LINELEN];
  1103.  
  1104.     usprintf(user->s,"%s\n",BBSversion);
  1105.  
  1106.     sprintf(buf,"%s/bbs.inf",BBSwrkdir);
  1107.  
  1108.     if((fp = Fopen(buf,READ_TEXT,0,0)) != NULLFILE) {
  1109.         while(fgets(buf,LINELEN,fp) != NULL) {
  1110.             usputs(user->s,buf);
  1111.         }
  1112.         Fclose(fp);
  1113.     }
  1114. }
  1115.  
  1116. #define nextarg(name)                            \
  1117.   if(!*(cp = getarg(0,0))) {                 \
  1118.     nname = name;                           \
  1119.     goto quit;                              \
  1120.   }                                         \
  1121.  
  1122. static void near
  1123. list_command(struct user *user)
  1124. {
  1125.   char *at = 0, *bid = 0, *from = 0, *mfrom = 0, *subject = 0, *to = 0, *cp, *nname = "";
  1126.   int arg = 2, found = 0, len, update_seq = 0;
  1127.   int32 count = 999999L, max = 999999L, min = 1;
  1128.   struct index index;
  1129.  
  1130.   getarg(user->line,0);
  1131.  
  1132.   while(*(cp = getarg(0,0))) {
  1133.     len = strlen(strlwr(cp));
  1134.  
  1135.     if(!strcmp("$", cp) || !strncmp("bid", cp, len)) {
  1136.       nextarg("BID");
  1137.       bid = strupr(cp);
  1138.     } else if (!strcmp("<", cp) || !strncmp("from", cp, len)) {
  1139.       nextarg("FROM");
  1140.       from = strupr(cp);
  1141.     } else if (!strcmp(">", cp) || !strncmp("to", cp, len)) {
  1142.       nextarg("TO");
  1143.       to = strupr(cp);
  1144.     } else if (!strcmp("@", cp) || !strncmp("at", cp, len)) {
  1145.       nextarg("AT");
  1146.       at = strupr(cp);
  1147.     } else if (!strncmp("count", cp, len)) {
  1148.       nextarg("COUNT");
  1149.       count = atol(cp);
  1150.     } else if (!strncmp("new", cp, len)) {
  1151.       min = user->info->seq + 1;
  1152.       update_seq = (arg++ == 2 && user->level != BOX);
  1153.     } else if (!strncmp("max", cp, len)) {
  1154.       nextarg("MAX");
  1155.       max = atol(cp);
  1156.     } else if (!strncmp("min", cp, len)) {
  1157.       nextarg("MIN");
  1158.       min = atol(cp);
  1159.     } else if (!strncmp("subject", cp, len)) {
  1160.       nextarg("SUBJECT");
  1161.       subject = cp;
  1162.     } else if (!strncmp("mfrom", cp, len)) {
  1163.       nextarg("MFROM");
  1164.       mfrom = strupr(cp);
  1165.     } else {
  1166.       to = strupr(cp);
  1167.     }
  1168.   }
  1169.   if(lseek(fdindex,-index_len,SEEK_END) >= 0) {
  1170.     int32 tindex_len = 2 * index_len;
  1171.  
  1172.     for (; ; ) {
  1173.       if(read(fdindex,&index,uindex_len) != uindex_len) {
  1174.         errorstop(20);
  1175.         return;
  1176.       }
  1177.       if(index.mesg < min) {
  1178.         break;
  1179.       }
  1180.       if(index.mesg <= max
  1181.        && read_allowed(&index,user)
  1182.        && (!bid     || !strcmp(index.bid,bid))
  1183.        && (!from    || strstr(index.from,from))
  1184.        && (!to      || strstr(index.to,to))
  1185.        && (!at      || strstr(index.at,at))
  1186.        && (!mfrom   || strstr(index.from_at,mfrom))
  1187.        && (!subject || strcasepos(index.subject,subject))) {
  1188.         if(!found) {
  1189.           usputs(user->s,"  Msg#  Size To       @BBS       From      Date    Subject\n");
  1190.           found = 1;
  1191.         }
  1192.         usprintf(user->s,"%6ld%6ld %-9.9s%c%-9.9s %-9.9s %-7.7s %.28s\n",
  1193.           index.mesg,
  1194.           index.size,
  1195.           index.to,
  1196.           *index.at ? '@' : ' ',
  1197.           index.at,
  1198.           index.from,
  1199.           timestr(index.date),
  1200.           index.subject);
  1201.  
  1202.         if(update_seq && user->info->seq < index.mesg) {
  1203.           user->info->seq = index.mesg;
  1204.         }
  1205.         if(--count <= 0) {
  1206.           break;
  1207.         }
  1208.       }
  1209.       if(lseek(fdindex,-tindex_len,SEEK_CUR) < 0) {
  1210.         break;
  1211.       }
  1212.     }
  1213.   }
  1214.   if(!found) {
  1215.     usputs(user->s,update_seq
  1216.       ? "No new messages since last LIST NEW command.\n"
  1217.       : "No matching message found.\n");
  1218.   }
  1219.   return;
  1220.  
  1221. quit:
  1222.   user->errors++;
  1223.   usprintf(user->s,errstr,nname,"LIST");
  1224.   return;
  1225. }
  1226.  
  1227. #undef nextarg
  1228.  
  1229. static void near
  1230. mybbs_command(struct user *user)
  1231. {
  1232.     char *cp;
  1233.  
  1234.     getarg(user->line,0);
  1235.     cp = getarg(0,0);
  1236.  
  1237.     if(!callvalid(strupr(cp))) {
  1238.         usprintf(user->s,Invcall,cp);
  1239.         return;
  1240.     }
  1241.     if(strcmp(user->info->mybbs,cp) != 0) {
  1242.         struct mail *mail = alloc_mail();
  1243.         sprintf(user->info->mybbs,"%.27s",cp);
  1244.         strcpy(mail->from,user->name);
  1245.         strcpy(mail->to,"m@thebox");
  1246.         sprintf(mail->subject,"%s %ld",cp,currtime);
  1247.         append_line(mail,"");
  1248.         route_mail(mail,user,BBS);
  1249.     }
  1250.     usprintf(user->s,"Setting MYBBS to %s.\n",cp);
  1251. }
  1252.  
  1253. static void near
  1254. name_command(struct user *user)
  1255. {
  1256.     char *cp;
  1257.  
  1258.     getarg(user->line,0);
  1259.     cp = getarg(0,0);
  1260.  
  1261.     *cp = toupper(*cp);
  1262.     sprintf(user->info->name,"%.27s",cp);
  1263. }
  1264.  
  1265. static void near
  1266. quit_command(struct user *user)
  1267. {
  1268.     user->level = CLOSED;
  1269. }
  1270.  
  1271. static void near
  1272. read_command(struct user *user)
  1273. {
  1274.   char *cp;
  1275.  
  1276.   getarg(user->line,0);
  1277.  
  1278.   while(*(cp = getarg(0,0))) {
  1279.     FILE *fp;
  1280.     char *p, buf[LINELEN], path[LINELEN];
  1281.     struct index index;
  1282.     int32 mesg = 0;
  1283.     int inheader;
  1284.  
  1285.     memset(&index,0,uindex_len);
  1286.  
  1287.     semwait(&Lock,1);
  1288.  
  1289.     if((mesg = atol(cp)) > 0
  1290.      && get_index(mesg,&index)
  1291.      && read_allowed(&index,user)) {
  1292.       semrel(&Lock);
  1293.  
  1294.       if((fp = Fopen(getfilename(mesg),READ_TEXT,0,1)) == NULLFILE) {
  1295.         return;
  1296.       }
  1297.       usprintf(user->s,"Msg# %ld  To: %s%s%s  From: %s @%s  Date: %s\n",
  1298.         index.mesg,
  1299.         index.to,
  1300.         *index.at ? " @" : "",
  1301.         index.at,
  1302.         index.from,
  1303.         index.from_at,
  1304.         timestr(index.date));
  1305.  
  1306.       if(*index.subject) {
  1307.         usprintf(user->s,"%s%s\n",Hdrs[SUBJECT],index.subject);
  1308.       }
  1309.       if(*index.bid) {
  1310.         usprintf(user->s,"%s%s\n",Hdrs[BULLID],index.bid);
  1311.       }
  1312.       *path = 0;
  1313.       inheader = 1;
  1314.  
  1315.       while(fgets(buf,LINELEN,fp) != NULL) {
  1316.         if(inheader) {
  1317.           if((p = get_host_from_header(buf)) != NULLCHAR) {
  1318.             strcat(path,*path ? "!" : Hdrs[PATH]);
  1319.             strcat(path,p);
  1320.             continue;
  1321.           }
  1322.           if(*path) {
  1323.             usprintf(user->s,"%s\n",path);
  1324.           }
  1325.           inheader = 0;
  1326.           usputs(user->s,"\n");
  1327.         }
  1328.         usputs(user->s,buf);
  1329.       }
  1330. done:
  1331.       Fclose(fp);
  1332.       usputs(user->s,"\n");
  1333.     } else {
  1334.       semrel(&Lock);
  1335.       usprintf(user->s,Nosuchmsg,cp);
  1336.     }
  1337.   }
  1338. }
  1339.  
  1340. static void near
  1341. reply_command(struct user *user)
  1342. {
  1343.   char *cp, *host = 0, *mesgstr = 0, *p = 0;
  1344.   int all = 0;
  1345.   int32 mesg = 0;
  1346.   struct index index;
  1347.   struct mail *mail;
  1348.  
  1349.   getarg(user->line,0);
  1350.  
  1351.   while(*(cp = getarg(0,0))) {
  1352.     if(stricmp(cp,"all") == 0) {
  1353.       all = 1;
  1354.     } else {
  1355.       mesg = atol(mesgstr = cp);
  1356.     }
  1357.   }
  1358.   if(!mesgstr) {
  1359.     usputs(user->s,"No message number specified.\n");
  1360.     return;
  1361.   }
  1362.   memset(&index,0,uindex_len);
  1363.  
  1364.   semwait(&Lock,1);
  1365.  
  1366.   if(mesg < 1 || !get_index(mesg,&index) || !read_allowed(&index,user)) {
  1367.     usprintf(user->s,Nosuchmsg,mesgstr);
  1368.     semrel(&Lock);
  1369.     return;
  1370.   }
  1371.   semrel(&Lock);
  1372.   mail = alloc_mail();
  1373.   strcpy(mail->from,user->name);
  1374.  
  1375.   if(all) {
  1376.     strcpy(mail->to,index.to);
  1377.     if(*index.at) {
  1378.       strcat(mail->to,"@");
  1379.       strcat(mail->to,index.at);
  1380.     }
  1381.   } else {
  1382.     FILE *fp;
  1383.     char *cp, line[MAXPATH];
  1384.  
  1385.     sprintf(mail->to,"%s@%s",index.from,index.from_at);
  1386.  
  1387.     if((cp = strchr(mail->to,' ')) != NULLCHAR) {
  1388.       *cp = '\0';
  1389.     }
  1390.     if(strcasepos(index.from_at,"BBS") != 0) {
  1391.       if((fp = Fopen(getfilename(mesg),READ_TEXT,0,1)) == NULLFILE) {
  1392.         free_mail(mail);
  1393.         return;
  1394.       }
  1395.       for(host = 0; fgets(line,MAXPATH,fp); host = p) {
  1396.         if((p = get_host_from_header(line)) == NULLCHAR) {
  1397.           break;
  1398.         }
  1399.       }
  1400.       Fclose(fp);
  1401.  
  1402.       if(host) {
  1403.         strcat(mail->to,"@");
  1404.         strcat(mail->to,host);
  1405.       }
  1406.     }
  1407.   }
  1408.   strlwr(mail->to);
  1409.  
  1410.   for(p = index.subject; ; ) {
  1411.     while(isspace(*p)) {
  1412.       p++;
  1413.     }
  1414.     if(strnicmp(p,"Re:",3) != 0) {
  1415.       break;
  1416.     }
  1417.     p += 3;
  1418.   }
  1419.   usprintf(user->s,"%s%s\n",Hdrs[TO],mail->to);
  1420.   sprintf(mail->subject,"Re: %s",p);
  1421.   usprintf(user->s,"%s%s\n",Hdrs[SUBJECT],mail->subject);
  1422.   usputs(user->s,Entermsg);
  1423.  
  1424.   for(; ; ) {
  1425.     if(!getstring(user)) {
  1426.       free_mail(mail);
  1427.       return;
  1428.     }
  1429.     if(check_eom(user->line,0)) {
  1430.         break;
  1431.     }
  1432.     append_line(mail,user->line);
  1433.  
  1434.     if(strchr(user->line,'\032')) {
  1435.       break;
  1436.     }
  1437.     if(strchr(user->line,'\001')) {
  1438.       free_mail(mail);
  1439.       return;
  1440.     }
  1441.   }
  1442.   usprintf(user->s,SendMsg,mail->to);
  1443.   route_mail(mail,user,MAIL);
  1444. }
  1445.  
  1446. #define nextarg(name)                            \
  1447.   if(isalnum(*(cp + 1))) {                    \
  1448.     cp++;                                   \
  1449.   } else if(!*(cp = getarg(0,0))) {         \
  1450.     nname = name;                           \
  1451.     goto quit1;                                \
  1452.   }
  1453.  
  1454. static void near
  1455. send_command(struct user *user)
  1456. {
  1457.   char *cp = getarg(user->line,0), *p, at[80], path[80], *nname = "";
  1458.   int check_header = 1;
  1459.   struct mail *mail = alloc_mail();
  1460.  
  1461.   if(user->level == BOX) {
  1462.     switch(tolower(*(cp + 1))) {
  1463.     default:
  1464.       mail->flag = PRIVATE;
  1465.       break;
  1466.     case 'b':
  1467.       mail->flag = BULLETIN;
  1468.       break;
  1469.     }
  1470.   }
  1471.   *at = *path = '\0';
  1472.  
  1473.   while(*(cp = getarg(0,0))) {
  1474.     if (*cp == '#') {
  1475.       nextarg("#");
  1476.       mail->lifetime = atoi(cp);
  1477.     } else if (*cp == '$') {
  1478.       nextarg("$");
  1479.       strcpy(mail->bid, cp);
  1480.     } else if (*cp == '<') {
  1481.       nextarg("<");
  1482.       strcpy(mail->from, cp);
  1483.     } else if (*cp == '>') {
  1484.       nextarg(">");
  1485.       strcpy(mail->to, cp);
  1486.     } else if (*cp == '@') {
  1487.       nextarg("@");
  1488.       strcpy(at, cp);
  1489.     } else {
  1490.       strcpy(mail->to, cp);
  1491.     }
  1492.   }
  1493.   if(!*mail->to || (user->level == USER && !mail->to[1])) {
  1494.     user->errors++;
  1495.     usputs(user->s,"No or invalid recipient specified\n");
  1496.     goto quit;
  1497.   }
  1498.   if(*at) {
  1499.     strcat(mail->to,"@");
  1500.     strcat(mail->to,at);
  1501.   }
  1502.   strlwr(mail->to);
  1503.  
  1504.   if(!*mail->from || user->level < BOX) {
  1505.     strcpy(mail->from,user->name);
  1506.   }
  1507.   if(*mail->bid) {
  1508.     mail->bid[LEN_BID - 1] = 0;
  1509.     strupr(mail->bid);
  1510.     if(!msg_uniq(mail->bid)) {
  1511.       usputs(user->s,"No\n");
  1512.       goto quit;
  1513.     }
  1514.   }
  1515.   usputs(user->s,(user->level == BOX) ? "OK\n" : "Enter subject: ");
  1516.  
  1517.   if(!getstring(user)) {
  1518.     goto quit;
  1519.   }
  1520.   strcpy(mail->subject,user->line);
  1521.   strtrim(mail->subject);
  1522.  
  1523.   if(!*mail->subject && user->level != BOX) {
  1524.     user->errors++;
  1525.     usputs(user->s,"No subject specified.\n");
  1526.     goto quit;
  1527.   }
  1528.   if(user->level != BOX) {
  1529.     usputs(user->s,Entermsg);
  1530.   }
  1531.   for (; ; ) {
  1532.     if(!getstring(user)) {
  1533.       goto quit;
  1534.     }
  1535.     if(check_eom(user->line,0)) {
  1536.       break;
  1537.     }
  1538.     if(!(check_header && user->line[0] == ' ' && user->line[1] == '[')) {
  1539.       append_line(mail,user->line);
  1540.       if (check_header) {
  1541.         if((p = get_host_from_header(user->line)) != NULLCHAR) {
  1542.           if (*path) {
  1543.             strcat(path, "!");
  1544.           }
  1545.           strcat(path, p);
  1546.         } else if (*path) {
  1547.           check_header = 0;
  1548.         }
  1549.       }
  1550.     }
  1551.     if(strchr(user->line,'\032')) {
  1552.       break;
  1553.     }
  1554.     if(strchr(user->line,'\001')) {
  1555.       goto quit;
  1556.     }
  1557.   }
  1558.   /* Insert customised signature if one is found */
  1559.   if(user->level != BOX) {        /* not a forwarding BBS */
  1560.     FILE *fp;
  1561.  
  1562.     sprintf(user->line,"%s/%s.sig",Signature,user->name);
  1563.  
  1564.     if((fp = Fopen(user->line,READ_TEXT,0,0)) != NULLFILE) {
  1565.       while(fgets(user->line,LINELEN,fp) != NULLCHAR) {
  1566.         append_line(mail,user->line);
  1567.       }
  1568.       Fclose(fp);
  1569.     }
  1570.   }
  1571.   if(*path) {
  1572.     strcpy(user->line,mail->from);
  1573.     sprintf(mail->from,"%s!%s",path,user->line);
  1574.   }
  1575.   if(user->level != BOX) {
  1576.     usprintf(user->s,SendMsg,mail->to);
  1577.   }
  1578.   route_mail(mail,user,MAIL);
  1579.   return;
  1580.  
  1581. quit1:
  1582.   user->errors++;
  1583.   usprintf(user->s,errstr,nname,"SEND");
  1584. quit:
  1585.   free_mail(mail);
  1586. }
  1587.  
  1588. #undef nextarg
  1589.  
  1590. static void near
  1591. status_command(struct user *user)
  1592. {
  1593.   struct index pi;
  1594.   int32 active = 0, crunchok = 0, deleted = 0, highest = 0;
  1595.   int32 new = 0, readable = 0, validdate = currtime - 90 * DAYS;
  1596.  
  1597.   usputs(user->s,BBSversion);
  1598.  
  1599.   usprintf(user->s,Userstr,
  1600.     user->name,user->info->name,user->info->mybbs,timestr(user->info->time));
  1601.  
  1602.   lseek(fdindex,0,SEEK_SET);
  1603.  
  1604.   while(read(fdindex,&pi,uindex_len) == uindex_len ) {
  1605.     highest = pi.mesg;
  1606.  
  1607.     if(pi.flag & DELETED) {
  1608.       deleted++;
  1609.  
  1610.       if(!*pi.bid || pi.date < validdate) {
  1611.         crunchok++;
  1612.       }
  1613.     } else {
  1614.       active++;
  1615.  
  1616.       if(read_allowed(&pi,user)) {
  1617.         readable++;
  1618.  
  1619.         if(pi.mesg > user->info->seq) {
  1620.           new++;
  1621.         }
  1622.       }
  1623.     }
  1624.   }
  1625.   usprintf(user->s,
  1626.     "%6ld  Highest message number\n"
  1627.     "%6ld  Active messages\n"
  1628.     "%6ld  Readable messages\n"
  1629.     "%6ld  Last message listed\n"
  1630.     "%6ld  New messages\n",
  1631.       highest,
  1632.       active,
  1633.       readable,
  1634.       user->info->seq,
  1635.       new);
  1636.   if(user->level == ROOT) {
  1637.     usprintf(user->s,
  1638.       "%6ld  Deleted messages\n"
  1639.       "%6ld  Messages may be crunched\n",
  1640.         deleted,
  1641.         crunchok);
  1642.   }
  1643. }
  1644.  
  1645. static void near
  1646. user_command(struct user *user)
  1647. {
  1648.   char *cp;
  1649.   struct user *u;
  1650.  
  1651.   getarg(user->line,0);
  1652.  
  1653.   cp = getarg(0,1);
  1654.  
  1655.   u = get_seq(strupr(cp),1);
  1656.  
  1657.   BbsUser++;
  1658.  
  1659.   if(u->info->seq == 0 && *u->info->mybbs == '\0') {
  1660.     usprintf(user->s,"User %s not known.\n",cp);
  1661.   } else {
  1662.     usprintf(user->s,Userstr,
  1663.       u->name,u->info->name,u->info->mybbs,timestr(u->info->time));
  1664.   }
  1665.   cleanup(u);
  1666. }
  1667.  
  1668. static void near
  1669. xcrunch_command(struct user *user)
  1670. {
  1671.   int f, wflag = 0;
  1672.   char tmpfile[MAXPATH], tempfile[MAXPATH];
  1673.   struct index index;
  1674.  
  1675.   sprintf(tempfile,"%s/%s",BBSwrkdir,Indexfile);
  1676.   sprintf(tmpfile,"%s.tmp",tempfile);
  1677.  
  1678.   semwait(&Lock,1);
  1679.  
  1680.   if((f = open(tmpfile,O_WRONLY | O_CREAT | O_BINARY,S_IREAD | S_IWRITE)) < 0) {
  1681.     goto quit;
  1682.   }
  1683.   lseek(fdindex,0,SEEK_SET);
  1684.  
  1685.   memset(&index,0,uindex_len);
  1686.  
  1687.   while(read(fdindex,&index,uindex_len) == uindex_len) {
  1688.     wflag = 1;
  1689.     if(!(index.flag & DELETED)
  1690.      || *index.bid && index.date >= (currtime - 90 * DAYS)) {
  1691.       if(write(f,&index,uindex_len) != uindex_len) {
  1692.         goto quit;
  1693.       }
  1694.       wflag = 0;
  1695.     }
  1696.     memset(&index,0,uindex_len);
  1697.   }
  1698.   if(wflag) {
  1699.     if(write(f,&index,uindex_len) != uindex_len) {
  1700.       goto quit;
  1701.     }
  1702.   }
  1703.   close(f);
  1704.   close(fdindex);
  1705.   unlink(tempfile);
  1706.  
  1707.   if(!(rename(tmpfile,tempfile))) {
  1708.     if((fdindex = open(tempfile,O_RDWR | O_CREAT | O_BINARY,S_IREAD | S_IWRITE)) > 0) {
  1709.       semrel(&Lock);
  1710.       usputs(user->s,"Crunching successfully finished\n");
  1711.       return;
  1712.     }
  1713.   }
  1714. quit:
  1715.   errorstop(26);
  1716.   semrel(&Lock);
  1717.   return;
  1718. }
  1719.  
  1720. #ifdef XXX
  1721. static void near
  1722. connect_bbs(struct user *user)
  1723. {
  1724.   char *address;
  1725.   int addrlen;
  1726.   int fd;
  1727.   struct sockaddr *addr;
  1728.  
  1729.   if ((address = connect_addr(user)) == NULLCHAR) return;
  1730.   if (!(addr = build_sockaddr("unix:/tcp/.sockets/netcmd", &addrlen))) return;
  1731.   if ((fd = socket(addr->sa_family, SOCK_STREAM, 0)) < 0) return;
  1732.   if (connect(fd, addr, addrlen)) return;
  1733.   if (fd != 0) dup2(fd, 0);
  1734.   if (fd != 1) dup2(fd, 1);
  1735.   if (fd != 2) dup2(fd, 2);
  1736.   if (fd > 2) close(fd);
  1737.   fdopen(0, "r+");
  1738.   fdopen(1, "r+");
  1739.   fdopen(2, "r+");
  1740.   usprintf(user->s,"connect %s\n", address);
  1741. }
  1742. #endif
  1743.  
  1744. static void near
  1745. parse_command_line(struct user *user)
  1746. {
  1747.   char *cp = user->line, *cp1;
  1748.   int arglen = 0;
  1749.  
  1750.   struct cmdtable *cmdp;
  1751.  
  1752.   while(isspace(*cp)) {
  1753.     cp++;
  1754.   }
  1755.   cp1 = cp;
  1756.  
  1757.   log(user->s,9980,user->line);
  1758.  
  1759.   if(*cp == '[') {
  1760.     char *sid_features;
  1761.  
  1762.     if(cp[strlen(cp) - 1] == ']') {
  1763.       /* must be an SID */
  1764.       user->sid = MBX_SID;
  1765.  
  1766.       /* Now check to see if this is an RLI board.
  1767.        * As usual, Hank does it a bit differently from the rest of the world.
  1768.        */
  1769.       if(cp[1] == 'R' && strncmp(&cp[1],"li",2) == 0) {
  1770.         /* [RLI] at a minimum */
  1771.         user->sid |= MBX_RLI_SID;
  1772.       }
  1773.       /* Check to see if the BBS supports a kludge called "hierarchical
  1774.        * routing designators."
  1775.        */
  1776.       sid_features = strrchr(cp,'-');
  1777.  
  1778.       if((sid_features != NULLCHAR)
  1779.        && (strlen(sid_features) > 3)
  1780.        && (strchr(sid_features,'h') != NULLCHAR)
  1781.        && (strchr(sid_features,'$') != NULLCHAR)) {
  1782.         user->sid |= MBX_HIER_SID;
  1783.       }
  1784.       return;
  1785.     }
  1786.   }
  1787.   while(*cp1 && !isspace(*cp1)) {
  1788.     cp1++;
  1789.     arglen++;
  1790.   }
  1791.   for(cmdp = cmdtable; cmdp->name; cmdp++) {
  1792.     if(strnicmp(cmdp->name,cp,arglen) == 0) {
  1793.       if(cmdp->argc && strchr(cp1,' ') == NULLCHAR) {
  1794.         if(++user->errors >= 3) {
  1795.           user->level = CLOSED;
  1796.         }
  1797.         usprintf(user->s,errstr,cmdp->name,cmdp->name);
  1798.       } else {
  1799.         user->errors = 0;
  1800.         (cmdp->func)(user);
  1801.       }
  1802.       return;
  1803.     }
  1804.   }
  1805.   /* Can't be a legal command */
  1806.   usputs(user->s,"Unknown command. Type ? for help.\n");
  1807.  
  1808.   if(user->level == BOX) {
  1809.     user->level = CLOSED;
  1810.   }
  1811.   return;
  1812. }
  1813.  
  1814. static int near
  1815. setup_vars(void)
  1816. {
  1817.     char *cp;
  1818.  
  1819.     if(*myhostname) {
  1820.         xfree(myhostname);
  1821.         xfree(MYHOSTNAME);
  1822.     }
  1823.     cp = myhostname = strxdup(Hostname);
  1824.  
  1825.     if((cp = strpbrk(myhostname,". @!")) != NULLCHAR) {
  1826.         *cp = '\0';
  1827.     }
  1828.     MYHOSTNAME = strxdup(myhostname);
  1829.  
  1830.     if((cp = strchr(MYHOSTNAME,'-')) != NULLCHAR) {
  1831.         *cp = '\0';
  1832.     }
  1833.     strupr(MYHOSTNAME);
  1834.  
  1835.     len_myhostname = strlen(myhostname);
  1836.     len_MYHOSTNAME = strlen(MYHOSTNAME);
  1837.  
  1838.     if(BbsUser == 0) {
  1839.         char fname[MAXPATH];
  1840.  
  1841.         sprintf(fname,"%s/%s",BBSwrkdir,Indexfile);
  1842.  
  1843.         if((fdindex = open(fname,O_RDWR | O_CREAT | O_BINARY,S_IREAD | S_IWRITE)) < 1) {
  1844.             errorstop(131);
  1845.             return 0;
  1846.         }
  1847.     }
  1848.     return ++BbsUser;
  1849. }
  1850.  
  1851. static void near
  1852. cleanup(struct user *user)
  1853. {
  1854.     xfree(user->line);
  1855.     xfree(user->name);
  1856.     xfree(user);
  1857.  
  1858.     if(--BbsUser < 1) {
  1859.         close(fdindex);
  1860.         fdindex = -1;
  1861.         xfree(myhostname);
  1862.         myhostname = NULLCHAR;
  1863.         xfree(MYHOSTNAME);
  1864.         MYHOSTNAME = NULLCHAR;
  1865.         BbsUser = 0;
  1866.     }
  1867. }
  1868.  
  1869. static struct user * near
  1870. get_seq(char *username,int flag)
  1871. {
  1872.     char *cp;
  1873.     struct user *u = mxallocw(sizeof(struct user));
  1874.  
  1875.     if(access(BBSwrkdir,0)) {
  1876.         mkdir(BBSwrkdir);
  1877.         if(access(BBSwrkdir,0)) {
  1878.             xfree(u);
  1879.             return 0;
  1880.         }
  1881.     }
  1882.     u->line = mxallocw(LINELEN);
  1883.     cp = u->name = strxdup(username);
  1884.  
  1885.     while(cp && isalnum(*cp)) {
  1886.         cp++;
  1887.     }
  1888.     *cp = '\0';
  1889.  
  1890.     if(flag) {
  1891.         int fp = -1;
  1892.         char fname[MAXPATH];
  1893.  
  1894.         struct userinfo *uinfo = mxallocw(uinfo_len);
  1895.  
  1896.         sprintf(fname,"%s/%s.rc",BBSwrkdir,username);
  1897.  
  1898.         if((fp = open(fname,O_RDONLY | O_BINARY,S_IFREG | S_IREAD)) < 0
  1899.           || read(fp,uinfo,uinfo_len) != uinfo_len) {
  1900.             *uinfo->mybbs = '\0';
  1901.             uinfo->time = currtime;
  1902.             uinfo->seq = 0;
  1903.         }
  1904.         if(fp != -1) {
  1905.             close(fp);
  1906.         }
  1907.         u->info = uinfo;
  1908.     }
  1909.     return u;
  1910. }
  1911.  
  1912. static void near
  1913. put_seq(struct user *user)
  1914. {
  1915.     int fp = -1;
  1916.     char fname[MAXPATH];
  1917.  
  1918.     sprintf(fname,"%s/%s.rc",BBSwrkdir,user->name);
  1919.  
  1920.     unlink(fname);        /* first delete the old file */
  1921.  
  1922.     user->info->time = currtime;
  1923.  
  1924.     if((fp = open(fname,O_CREAT | O_WRONLY | O_BINARY,S_IFREG | S_IWRITE)) < 0
  1925.       || write(fp,user->info,uinfo_len) != uinfo_len) {
  1926.         /* if something is wrong, delete if something is on the disk */
  1927.         unlink(fname);
  1928.     }
  1929.     if(fp != -1) {
  1930.         close(fp);
  1931.     }
  1932. }
  1933.  
  1934. int
  1935. recv_from_mail_or_news(FILE *data,char *from,char *to)
  1936. {
  1937.   char *cp, distr[80], exp[80];
  1938.   int fail = -1, from_priority = 0, state = 0;
  1939.   int32 n = 0x7fffffffL;
  1940.  
  1941.   struct mail *mail = alloc_mail();
  1942.   struct user *user = get_seq(from,0);
  1943.  
  1944.   if(!setup_vars()) {
  1945.     return fail;
  1946.   }
  1947.   if((cp = strchr(user->name,'@')) != NULLCHAR) {
  1948.     *cp = '\0';
  1949.   }
  1950.   *distr = '\0';
  1951.  
  1952.   sprintf(mail->to,"%.*s",LEN+LEN,to);
  1953.  
  1954.   while(fgets(user->line,LINELEN,data)) {
  1955.     switch(state) {
  1956.     case 0:
  1957.       rip(user->line);
  1958.       if(*user->line) {
  1959.         if(from_priority < 1
  1960.          && !strncmp(user->line,"From ",5)
  1961.          && sscanf(user->line,"From %s",mail->from) == 1) {
  1962.           from_priority = 1;
  1963.         }
  1964.         if(from_priority < 2
  1965.          && get_header_value(Hdrs[PATH],user->line,mail->from)) {
  1966.           from_priority = 2;
  1967.         }
  1968.         if(from_priority < 3
  1969.          && get_header_value(Hdrs[FROM],user->line,mail->from)) {
  1970.           from_priority = 3;
  1971.         }
  1972.         if(get_header_value(Hdrs[NEWSGROUPS],user->line,mail->newsgroup)) {
  1973.           mail->flag = NEWS;
  1974.         }
  1975.         get_header_value(Hdrs[SUBJECT],user->line,mail->subject);
  1976.         get_header_value(Hdrs[MSGID],user->line,mail->mid);
  1977.         if(get_header_value(Hdrs[DISTRIBUTION],user->line,distr)) {
  1978.           mail->flag = NEWS;
  1979.         }
  1980.         get_header_value(Hdrs[BULLID],user->line,mail->bid);
  1981.         if(get_header_value(Hdrs[EXPIRE],user->line,exp)) {
  1982. /* */
  1983.         }
  1984.       } else {
  1985.         state = 1;
  1986.       }
  1987.       break;
  1988.     case 1:
  1989.       if(!*user->line) {
  1990.         break;
  1991.       }
  1992.       state = 2;
  1993.     case 2:
  1994.       append_line(mail,user->line);
  1995.     }
  1996.     if(n <= 0) {
  1997.       break;
  1998.     }
  1999.     n -= strlen(user->line);
  2000.     strtrim(user->line);
  2001.   }
  2002.   if(*mail->to && from_priority && state == 2) {
  2003.     if(!strncmp(mail->to,"ampr.bbs.",9)) {
  2004.       strcpy(mail->to,mail->to + 9);
  2005.     }
  2006.     if((cp = strchr(mail->to,',')) != NULLCHAR) {
  2007.       *cp = 0;
  2008.     }
  2009.     if((cp = strrchr(mail->to,'.'))!= NULLCHAR) {
  2010.       strcpy(mail->to, cp + 1);
  2011.     }
  2012.     if((cp = strchr(distr,',')) != NULLCHAR) {
  2013.       *cp = 0;
  2014.     }
  2015.     if((cp = strrchr(distr,'.')) != NULLCHAR) {
  2016.       strcpy(distr, cp + 1);
  2017.     }
  2018.     if(*distr) {
  2019.       strcat(mail->to,"@");
  2020.       strcat(mail->to,distr);
  2021.     }
  2022.     route_mail(mail,user,BBS);
  2023.     fail = 0;
  2024.   } else {
  2025.     free_mail(mail);
  2026.   }
  2027.   cleanup(user);
  2028.  
  2029.   return fail;
  2030. }
  2031.  
  2032. #include "mailbox.h"
  2033.  
  2034. int
  2035. dombbs(int argc,char **argv,void *p)
  2036. {
  2037.   FILE *fp;
  2038.   char line [MAXPATH];
  2039.   struct mbx *m = (struct mbx *)p;
  2040.   struct user *user = get_seq(m->name,1);
  2041.   int oldf = setflush((user->s = m->user),'\n');
  2042.  
  2043.   m->state = MBX_BBS;
  2044.  
  2045.   if(!setup_vars()) {
  2046.     return -1;
  2047.   }
  2048.   if(argc == 0x10) {
  2049.     user->level = BOX;
  2050.   }
  2051.   if(user->level != BOX) {
  2052.     if(m->perms & SYSOP_CMD) {
  2053.       user->level = ROOT;
  2054.     }
  2055.   }
  2056.   sprintf(line,"%s/%s.cfg",BBSwrkdir,user->name);
  2057.  
  2058.   if((fp = Fopen(line,READ_TEXT,0,0)) != NULLFILE) {
  2059.     while(fgets(user->line,LINELEN,fp) != NULL) {
  2060.       parse_command_line(user);
  2061.     }
  2062.     Fclose(fp);
  2063.   } else {
  2064.     if(user->level != BOX) {
  2065.       usprintf(user->s,"%s\nType '?' for help.\n",BBSversion);
  2066.     }
  2067.   }
  2068.   for(; ; ) {
  2069.     if(user->level == CLOSED) {
  2070.       usputs(user->s,"BBS terminated\n");
  2071.       break;
  2072.     }
  2073.     usprintf(user->s,user->level == BOX ? ">\n" : "%s-bbs>",myhostname);
  2074.  
  2075.     if(mbxrecvline(m) == EOF) {
  2076.       /* He closed on us */
  2077.       goto quit;
  2078.     }
  2079.     strcpy(user->line,m->line);
  2080.  
  2081.     if(!*user->line) {
  2082.       continue;
  2083.     }
  2084.     parse_command_line(user);
  2085.   }
  2086. quit:
  2087.   put_seq(user);
  2088.   xfree(user->info);
  2089.   cleanup(user);
  2090.   setflush(m->user,oldf);
  2091.   return 0;
  2092. }
  2093.  
  2094. /* -------------------------- S&F - Subcmds ------------------------------- */
  2095.  
  2096. #ifdef AX25
  2097. /* Set the Info field of R: header (eg forward info "[Bath, Avon - WNOS]") */
  2098. int
  2099. dofinfo(int argc,char **argv,void *p)
  2100. {
  2101.     if(argc < 2 && FInfo != NULLCHAR) {
  2102.         tprintf("FBBS Info: %s\n", FInfo);
  2103.     } else {
  2104.         if(FInfo != NULLCHAR) {
  2105.             xfree(FInfo);
  2106.         }
  2107.         FInfo = strxdup(argv[1]);
  2108.     }
  2109.     return 0;
  2110. }
  2111.  
  2112. /* Set Nic field of R: header (eg forward nic ".GB7IMB.#41.GBR.EU" */
  2113. int
  2114. dofnic(int argc,char **argv,void *p)
  2115. {
  2116.     if(argc < 2 && FNic != NULLCHAR) {
  2117.         tprintf("FNIC Id: %s\n", FNic);
  2118.     } else {
  2119.         if(FNic != NULLCHAR) {
  2120.             xfree(FNic);
  2121.         }
  2122.         FNic = strxdup(argv[1]);
  2123.         strupr(FNic);
  2124.     }
  2125.     return 0;
  2126. }
  2127.  
  2128. int
  2129. dofkick(int argc,char **argv,void *p)
  2130. {
  2131.  
  2132.  
  2133.     return 0;
  2134. }
  2135.  
  2136. #endif
  2137.  
  2138. #endif
  2139.